<template>
  <div class="custom-upload-container">
    <!-- 上传区域 -->
    <el-upload
      ref="uploadRef"
      v-bind="uploadProps"
      :class="{ 'drop-active': dropActive }"
      :headers="headers"
      :action="actionUrl"
      :data="uploadData"
      :limit="limit"
      :disabled="disabled"
      :multiple="multiple"
      :accept="accept"
      :auto-upload="autoUpload"
      :file-list="fileList"
      :list-type="listType"
      :show-file-list="showFileList && displayType !== 'custom'"
      :drag="displayType === 'drag'"
      :on-preview="onPreviewFile"
      :on-remove="onRemoveFile"
      :on-success="onUploadSuccess"
      :on-error="onUploadError"
      :on-exceed="onExceed"
      :before-upload="beforeUpload"
      :on-change="onChange"
      @dragover="dropActive = true"
      @dragleave="dropActive = false"
      @drop="dropActive = false"
    >
      <!-- 拖拽上传 -->
      <template v-if="displayType === 'drag'">
        <div class="drop-area">
          <el-icon class="drop-icon"><Upload /></el-icon>
          <div class="drop-text">将文件拖到此处，或<em>点击上传</em></div>
          <div v-if="tip" class="drop-tip">{{ tip }}</div>
        </div>
      </template>

      <!-- 按钮上传 -->
      <template v-else-if="displayType === 'button'">
        <el-button :type="buttonType" :size="size" :disabled="disabled || isLimitExceeded">
          <el-icon><Upload /></el-icon>
          <span>{{ buttonText }}</span>
        </el-button>
        <div v-if="tip" class="upload-tip">{{ tip }}</div>
      </template>

      <!-- 图片墙上传 -->
      <template v-else-if="displayType === 'picture-wall' && listType === 'picture-card'">
        <div class="upload-picture-card-wrapper">
          <el-icon><Plus /></el-icon>
        </div>
        <div v-if="tip" class="upload-tip">{{ tip }}</div>
      </template>
    </el-upload>

    <!-- 自定义文件列表展示模式 -->
    <div v-if="displayType === 'custom' && showFileList" class="custom-file-list">
      <div v-if="fileList.length === 0 && emptyText" class="no-file">{{ emptyText }}</div>
      <div v-for="(file, index) in fileList" :key="file.uid || index" class="file-item">
        <div class="file-item-icon">
          <el-icon
            v-if="getFileTypeIcon(file.name)"
            class="file-type-icon"
            :class="getFileTypeClass(file.name)"
          >
            <component :is="getFileTypeIcon(file.name)" />
          </el-icon>
          <el-image
            v-else-if="getFileType(file.name) === 1"
            :src="file.url"
            :preview-src-list="[file.url]"
            fit="cover"
            class="file-thumbnail"
          />
          <el-icon v-else class="file-type-icon"><Document /></el-icon>
        </div>
        <div class="file-item-info">
          <div class="file-name" :title="file.name">{{ file.name }}</div>
          <div class="file-size">{{ formatFileSize(file.size) }}</div>
          <el-progress
            v-if="file.status === 'uploading'"
            :percentage="file.percentage || 0"
            :stroke-width="2"
            class="upload-progress"
          />
        </div>
        <div class="file-item-actions">
          <el-button
            v-if="file.status === 'success'"
            type="primary"
            link
            @click="onPreviewFile(file)"
          >
            <el-icon><ZoomIn /></el-icon>
          </el-button>
          <el-button v-if="!disabled" type="danger" link @click="onRemoveFile(file)">
            <el-icon><Delete /></el-icon>
          </el-button>
        </div>
      </div>

      <!-- 自定义上传按钮 -->
      <div v-if="!isLimitExceeded" class="custom-upload-button" @click="triggerUpload">
        <el-button :type="buttonType" :size="size" :disabled="disabled">
          <el-icon><Upload /></el-icon>
          <span>{{ buttonText }}</span>
        </el-button>
      </div>
    </div>

    <!-- 自定义操作区域 -->
    <div v-if="showActions && !disabled" class="upload-actions">
      <slot name="actions">
        <el-button
          v-if="fileList.length > 0 && autoUpload === false"
          type="primary"
          :size="size"
          @click="submitUpload"
        >
          开始上传
        </el-button>
        <el-button v-if="fileList.length > 0" :size="size" @click="clearFiles">
          清空列表
        </el-button>
      </slot>
    </div>

    <!-- 预览对话框 -->
    <preview-dialog
      v-if="showPreview"
      :visible="showPreview"
      :file-list="previewFileList"
      :default-index="previewIndex"
      :readonly="!supportDownload"
      @close="showPreview = false"
    />
  </div>
</template>

<script setup>
import { ref, computed, onMounted, watchEffect } from 'vue';
import { ElMessage } from 'element-plus';
import { serverDefaultCfg } from '@/common/http/config';
import { useUpload } from '@/common/hooks/useUpload';
import { useDownload } from '@/common/hooks/useDownload';
import { Plus, Upload, Document, Delete, ZoomIn } from '@element-plus/icons-vue';
import { getFileType } from '@/common/utils';
import PreviewDialog from '@/components/Preview/Dialog.vue';

// 定义组件属性
const props = defineProps({
  // 双向绑定值
  modelValue: {
    type: Array,
    default: () => [],
  },
  // 上传地址
  action: {
    type: String,
    default: serverDefaultCfg.ossURL,
  },
  // 上传时附带的额外参数
  data: {
    type: Object,
    default: () => ({}),
  },
  // 设置上传的请求头
  headers: {
    type: Object,
    default: () => ({}),
  },
  // 限制文件上传数量
  limit: {
    type: Number,
    default: 0,
  },
  // 是否禁用
  disabled: {
    type: Boolean,
    default: false,
  },
  // 是否支持多选文件
  multiple: {
    type: Boolean,
    default: true,
  },
  // 接受上传的文件类型
  accept: {
    type: String,
    default: '',
  },
  // 是否显示已上传文件列表
  showFileList: {
    type: Boolean,
    default: true,
  },
  // 是否启用自动上传
  autoUpload: {
    type: Boolean,
    default: true,
  },
  // 上传显示类型: 'button', 'drag', 'picture-wall', 'custom'
  displayType: {
    type: String,
    default: 'button',
  },
  // 文件列表的类型: 'text', 'picture', 'picture-card'
  listType: {
    type: String,
    default: 'text',
  },
  // 按钮类型
  buttonType: {
    type: String,
    default: 'primary',
  },
  // 按钮大小
  size: {
    type: String,
    default: 'default',
  },
  // 按钮文本
  buttonText: {
    type: String,
    default: '上传文件',
  },
  // 提示文本
  tip: {
    type: String,
    default: '',
  },
  // 空数据文本
  emptyText: {
    type: String,
    default: '暂无文件',
  },
  // 文件类型筛选
  fileTypes: {
    type: Array,
    default: () => [],
  },
  // 是否支持预览
  supportPreview: {
    type: Boolean,
    default: true,
  },
  // 是否支持下载
  supportDownload: {
    type: Boolean,
    default: true,
  },
  // 是否显示操作区域
  showActions: {
    type: Boolean,
    default: false,
  },
  // 自定义上传前验证
  beforeUploadValidator: {
    type: Function,
    default: null,
  },
});

const emit = defineEmits([
  'update:modelValue',
  'change',
  'success',
  'error',
  'exceed',
  'preview',
  'remove',
]);

const { downloadFile } = useDownload();

// 响应式数据
const uploadRef = ref(null);
const fileList = ref([]);
const dropActive = ref(false);
const showPreview = ref(false);
const previewIndex = ref(0);
const previewFileList = ref([]);
const uploadProps = ref({});

// 计算属性
const isLimitExceeded = computed(() => {
  return props.limit > 0 && fileList.value.length >= props.limit;
});

const actionUrl = computed(() => {
  return props.action;
});

const uploadData = computed(() => {
  return props.data || {};
});

// 格式化文件大小
const formatFileSize = size => {
  if (size == null) return '';
  if (size < 1024) {
    return size + 'B';
  } else if (size < 1024 * 1024) {
    return (size / 1024).toFixed(1) + 'KB';
  } else if (size < 1024 * 1024 * 1024) {
    return (size / 1024 / 1024).toFixed(1) + 'MB';
  } else {
    return (size / 1024 / 1024 / 1024).toFixed(1) + 'GB';
  }
};

// 获取文件类型图标
const getFileTypeIcon = fileName => {
  const fileType = getFileType(fileName);
  if (fileType === 1) {
    return PictureIcon;
  } else if (fileType === 3) {
    return VideoPlay;
  } else if (fileType === 4) {
    return Document;
  } else if (fileType === 5) {
    return Document;
  } else if (fileType === 6) {
    return Document;
  } else {
    return Document;
  }
};

// 获取文件类型样式类
const getFileTypeClass = fileName => {
  const fileType = getFileType(fileName);
  if (fileType === 1) {
    return 'is-image';
  } else if (fileType === 3) {
    return 'is-video';
  } else if (fileType === 4) {
    return 'is-pdf';
  } else if (fileType === 5) {
    return 'is-word';
  } else if (fileType === 6) {
    return 'is-excel';
  } else {
    return 'is-file';
  }
};

// 触发上传
const triggerUpload = () => {
  if (uploadRef.value) {
    uploadRef.value.handleClick();
  }
};

// 提交上传
const submitUpload = () => {
  if (uploadRef.value) {
    uploadRef.value.submit();
  }
};

// 清空文件列表
const clearFiles = () => {
  if (uploadRef.value) {
    uploadRef.value.clearFiles();
    fileList.value = [];
    emit('update:modelValue', []);
    emit('change', []);
  }
};

// 上传前的处理
const beforeUpload = file => {
  // 自定义验证
  if (props.beforeUploadValidator && typeof props.beforeUploadValidator === 'function') {
    const result = props.beforeUploadValidator(file);
    if (result !== true) {
      ElMessage.error(result || '文件验证失败');
      return false;
    }
  }

  // 文件类型筛选
  if (props.fileTypes && props.fileTypes.length > 0) {
    const fileType = getFileType(file.name);
    if (!props.fileTypes.includes(fileType)) {
      ElMessage.error('不支持的文件类型');
      return false;
    }
  }

  return true;
};

// 文件状态改变时处理
const onChange = (file, uploadFiles) => {
  fileList.value = uploadFiles;
  emit('change', uploadFiles);
};

// 文件上传成功处理
const onUploadSuccess = (response, file, uploadFiles) => {
  if (response.success) {
    file.downloadUri = response.data.downloadUri;
    file.filename = response.data.filename;
    file.uploadPath = response.data.uploadPath;
    file.url = URL.createObjectURL(file.raw);

    // 更新文件列表
    fileList.value = uploadFiles;

    // 提交更新后的数据
    updateModelValue();

    emit('success', response, file, uploadFiles);
  } else {
    ElMessage.error(response.message || '上传失败');
    emit('error', response, file, uploadFiles);
  }
};

// 文件上传错误处理
const onUploadError = (error, file, fileList) => {
  ElMessage.error('文件上传失败');
  emit('error', error, file, fileList);
};

// 上传超出限制处理
const onExceed = (files, uploadFiles) => {
  ElMessage.warning(`最多只能上传${props.limit}个文件`);
  emit('exceed', files, uploadFiles);
};

// 预览文件
const onPreviewFile = file => {
  if (props.supportPreview) {
    // 创建预览列表
    previewFileList.value = fileList.value
      .filter(item => item.url)
      .map(item => ({
        ...item,
        type: getFileType(item.name),
      }));

    // 获取当前文件索引
    previewIndex.value = previewFileList.value.findIndex(item => item.uid === file.uid);

    // 显示预览对话框
    showPreview.value = true;

    emit('preview', file);
  } else if (props.supportDownload) {
    downloadFile(file.url, file.name);
  }
};

// 移除文件
const onRemoveFile = (file, uploadFiles) => {
  if (uploadFiles) {
    fileList.value = uploadFiles;
  } else {
    const index = fileList.value.findIndex(item => item.uid === file.uid);
    if (index !== -1) {
      fileList.value.splice(index, 1);
    }
  }

  // 更新数据
  updateModelValue();

  emit('remove', file, fileList.value);
};

// 更新双向绑定的值
const updateModelValue = () => {
  const updatedValue = fileList.value
    .filter(file => file.status === 'success')
    .map(item => ({
      name: item.name,
      downloadUri:
        item.downloadUri || (item.response && item.response.data && item.response.data.downloadUri),
      filename:
        item.filename || (item.response && item.response.data && item.response.data.filename),
      uploadPath:
        item.uploadPath || (item.response && item.response.data && item.response.data.uploadPath),
      url:
        item.downloadUri || (item.response && item.response.data && item.response.data.downloadUri),
    }));

  emit('update:modelValue', updatedValue);
};

// 暴露方法给父组件使用
defineExpose({
  uploadRef,
  submitUpload,
  clearFiles,
  triggerUpload,
});

// 监听modelValue变化，更新fileList
watchEffect(() => {
  if (props.modelValue && Array.isArray(props.modelValue)) {
    fileList.value = props.modelValue.map((item, index) => {
      const fileItem = {
        ...item,
        uid: item.uid || `file-${index}`,
        status: 'success',
      };

      // 确保url属性存在，优先使用url，如果没有则使用downloadUri
      if (!fileItem.url && fileItem.downloadUri) {
        fileItem.url = fileItem.downloadUri;
      }

      return fileItem;
    });
  } else {
    fileList.value = [];
  }
});

onMounted(() => {
  // 根据不同的显示类型设置不同的上传属性
  if (props.displayType === 'picture-wall') {
    uploadProps.value = { listType: 'picture-card' };
  }
});
</script>

<style lang="scss" scoped>
.custom-upload-container {
  width: 100%;

  .drop-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 0;

    .drop-icon {
      font-size: 42px;
      color: #8c939d;
      margin-bottom: 16px;
    }

    .drop-text {
      font-size: 16px;
      color: #606266;
      margin-bottom: 8px;

      em {
        color: var(--el-color-primary);
        font-style: normal;
      }
    }

    .drop-tip {
      font-size: 13px;
      color: #909399;
    }
  }

  .upload-tip {
    font-size: 13px;
    color: #909399;
    margin-top: 8px;
  }

  .upload-actions {
    margin-top: 16px;
    display: flex;
    gap: 10px;
  }

  .custom-file-list {
    margin-top: 16px;

    .no-file {
      color: #909399;
      font-size: 14px;
      text-align: center;
      padding: 20px 0;
    }

    .file-item {
      display: flex;
      align-items: center;
      margin-bottom: 8px;
      padding: 8px 12px;
      border-radius: 4px;
      background-color: #f8f9fc;
      transition: background-color 0.2s;

      &:hover {
        background-color: #ecf2fe;
      }

      .file-item-icon {
        flex: 0 0 38px;
        height: 38px;
        margin-right: 12px;
        display: flex;
        align-items: center;
        justify-content: center;

        .file-type-icon {
          font-size: 24px;

          &.is-image {
            color: #55aaff;
          }
          &.is-video {
            color: #ff8a65;
          }
          &.is-pdf {
            color: #ff5252;
          }
          &.is-word {
            color: #3f51b5;
          }
          &.is-excel {
            color: #4caf50;
          }
          &.is-file {
            color: #607d8b;
          }
        }

        .file-thumbnail {
          width: 38px;
          height: 38px;
          object-fit: cover;
          border-radius: 4px;
        }
      }

      .file-item-info {
        flex: 1;
        overflow: hidden;

        .file-name {
          font-size: 14px;
          color: #303133;
          margin-bottom: 4px;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        .file-size {
          font-size: 12px;
          color: #909399;
        }

        .upload-progress {
          margin-top: 6px;
        }
      }

      .file-item-actions {
        flex: 0 0 auto;
        display: flex;
        gap: 4px;
      }
    }

    .custom-upload-button {
      margin-top: 16px;
    }
  }

  .drop-active {
    :deep(.el-upload-dragger) {
      border-color: var(--el-color-primary);
      background-color: var(--el-color-primary-light-9);
    }
  }
}
</style>
